package pikasial.graphique;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.ListIterator;
import java.util.Vector;
import java.util.concurrent.ExecutionException;

import javax.swing.AbstractAction;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.JToolBar;
import javax.swing.JWindow;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import pikasial.images.ImageContainer;
import pikasial.images.PikImage;
import pikasial.images.traitements.RescaleTraitement;
import pikasial.images.traitements.RotateTraitement;
import pikasial.utils.ChargeurImages;

@SuppressWarnings("serial")
public class Diaporama extends JWindow {

    private JToolBar controles;
    private JLabel diaporama;
    private JButton prec;
    private JButton suiv;
    private JButton pause;
    private boolean arrete;
    private JPopupMenu popup;
    private JMenuItem preced,  suivant,  stop;
    private ListIterator<PikImage> iterator;
    private BufferedImage currentImage;
    private BufferedImage prevImage;
    private BufferedImage nextImage;
    private int screenWidth;
    private int screenHeight;
    private boolean inRotation;
    private RotateTraitement rotate;

    // Icones
    private ImageIcon precedIcon;
    private ImageIcon suivantIcon;
    private ImageIcon pauseIcon;
    private ImageIcon continueIcon;
    private ImageIcon rotateLeftIcon;
    private ImageIcon rotateRightIcon;
    private ImageIcon exitIcon;

    public Diaporama(ImageContainer ic) {
        super(pikasial.Pikasial.getFrame());
        iterator = new Vector<PikImage>(ic.getAllImages()).listIterator();
        Toolkit tk = Toolkit.getDefaultToolkit();
        Dimension d = tk.getScreenSize();
        screenHeight = (int) d.getHeight();
        screenWidth = (int) d.getWidth();
        inRotation = false;
        precedIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.PREVIOUS_ICON_PATH));
        suivantIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.NEXT_ICON_PATH));
        pauseIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.PAUSE_ICON_PATH));
        continueIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.PLAY_ICON_PATH));
        rotateLeftIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ROTATE_LEFT_ICON_PATH));
        rotateRightIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.ROTATE_RIGHT_ICON_PATH));
        exitIcon = new ImageIcon(getClass().getResource(pikasial.utils.PikasialConstantes.CLOSE_ICON_PATH));
        initPopupMenu();
        initComponents();
        registerKeyboardAction();
        setSize(screenWidth, screenHeight);
    }

    private void initPopupMenu() {
        popup = new JPopupMenu();
        JMenuItem rotateLeft, rotateRight, quitter;
        preced = new JMenuItem("Image précédente", 'p');
        preced.setIcon(precedIcon);
        preced.setIcon(precedIcon);
        preced.setEnabled(false);
        preced.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                setArrete(true);
                Diaporama.this.imagePrecedente();
            }
        });
        suivant = new JMenuItem("Image suivante", 's');
        suivant.setIcon(suivantIcon);
        suivant.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                setArrete(true);
                Diaporama.this.imageSuivante();
            }
        });
        stop = new JMenuItem("Pause", 'a');
        stop.setIcon(pauseIcon);
        stop.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                setArrete(!isArrete());
            }
        });
        quitter = new JMenuItem("Quitter le diaporama", 'q');
        quitter.setIcon(exitIcon);
        quitter.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                dispose();
            }
        });
        rotateLeft = new JMenuItem("Rotation à gauche");
        rotateLeft.setIcon(rotateLeftIcon);
        rotateLeft.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
            	setArrete(true);
                Diaporama.this.rotateLeft();
            }
        });
        rotateRight = new JMenuItem("Rotation à droite");
        rotateRight.setIcon(rotateRightIcon);
        rotateRight.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
            	setArrete(true);
                Diaporama.this.rotateRight();
            }
        });
        popup.add(preced);
        popup.add(suivant);
        popup.addSeparator();
        popup.add(stop);
        popup.addSeparator();
        popup.add(rotateLeft);
        popup.add(rotateRight);
        popup.addSeparator();
        popup.add(quitter);
    }

    private void initComponents() {
        getContentPane().setLayout(new BorderLayout());
        getContentPane().setBackground(Color.BLACK);
        diaporama = new JLabel();
        diaporama.setHorizontalAlignment(JLabel.CENTER);
        diaporama.setVerticalAlignment(JLabel.CENTER);
        diaporama.addMouseListener(new MouseAdapter() {
            public void mouseReleased(MouseEvent e) {
                if (e.getButton() == MouseEvent.BUTTON3) {
                    popup.show(e.getComponent(), e.getX(), e.getY());
                }
            }
        });
        controles = new JToolBar();
        controles.setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5));
        controles.setFloatable(false);

        prec = new JButton("Image précédente",precedIcon);
        prec.setEnabled(false);
        prec.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                setArrete(true);
                Diaporama.this.imagePrecedente();
            }
        });
        suiv = new JButton("Image suivante",suivantIcon);
        suiv.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                setArrete(true);
                Diaporama.this.imageSuivante();
            }
        });
        JButton quit = new JButton("Quitter le diaporama",exitIcon);
        quit.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                Diaporama.this.dispose();
            }
        });
        pause = new JButton("Pause",pauseIcon);
        pause.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                setArrete(!isArrete());
            }
        });

        JButton rotateLeft, rotateRight;
        rotateLeft = new JButton("Rotation à gauche",rotateLeftIcon);
        rotateLeft.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
            	setArrete(true);
                Diaporama.this.rotateLeft();
            }
        });

        rotateRight = new JButton("Rotation à droite",rotateRightIcon);
        rotateRight.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                setArrete(true);
            	Diaporama.this.rotateRight();
            }
        });

        controles.add(prec);
        controles.add(pause);
        controles.add(suiv);
        controles.addSeparator();
        controles.add(rotateLeft);
        controles.add(rotateRight);
        controles.addSeparator();
        controles.add(quit);
        getContentPane().add(diaporama, BorderLayout.CENTER);
        getContentPane().add(controles, BorderLayout.SOUTH);
    }

    public void afficher() {
        setVisible(true);
        toFront();
        imageSuivante();
    }

    public void afficherImage(PikImage image) {
    	try {
    		currentImage = rescaleImage(ChargeurImages.getInstance().chargerImage(image));

    		if (currentImage != null) {
    			pause.setEnabled(false);
    			prec.setEnabled(false);
    			suiv.setEnabled(false);
    			popup.setEnabled(false);
    			SwingUtilities.invokeLater(new Runnable() {
    				public void run() {
    					diaporama.setIcon(new ImageIcon(currentImage));
    				}
    			});
    		}
    	} catch (ExecutionException e) {
    		JOptionPane.showMessageDialog(this,
                    "Impossible d'ouvrir l'image "
                    + image.getPath() + " !", "Erreur !",
                    JOptionPane.ERROR_MESSAGE);
    	}
    }

    protected void registerKeyboardAction() {
    	AbstractAction leftAction,rightAction,escapeAction;
    	rightAction = new AbstractAction() {
			public void actionPerformed(ActionEvent arg0) {
				setArrete(true);
				imageSuivante();
			}
    	};
    	leftAction = new AbstractAction() {
			public void actionPerformed(ActionEvent arg0) {
				setArrete(true);
				imagePrecedente();
			}
    	};
    	escapeAction = new AbstractAction() {
			public void actionPerformed(ActionEvent arg0) {
				dispose();
			}
    	};
    	String right = "fleched",left = "flecheg",escape = "echap";
    	getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_D,0), right);
    	getRootPane().getActionMap().put(right,rightAction);
    	getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_Q,0),left);
    	getRootPane().getActionMap().put(left, leftAction);
    	getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0), escape);
    	getRootPane().getActionMap().put(escape, escapeAction);
    }

    protected void setArrete(boolean b) {
        synchronized (this) {
            arrete = b;
            if (!arrete) { notifyAll(); System.out.println("notified"); }
        }
        if (b) {
        	stop.setIcon(continueIcon);
        	pause.setIcon(continueIcon);
            stop.setText("Reprendre le diaporama");
            pause.setText("Reprendre le diaporama");
        } else {
        	pause.setIcon(pauseIcon);
        	stop.setIcon(pauseIcon);
            stop.setText("Pause");
            pause.setText("Pause");
        }
    }

    public synchronized boolean isArrete() {
        return arrete;
    }

    public void diaporama() {
        arrete = false;
        new Thread(new Runnable() {
            public void run() {
            	try { Thread.sleep(4000); } catch (InterruptedException ie) {}
                while (iterator.hasNext()) {
                	try {
                		while (isArrete()) {
                			synchronized(this) {
                				wait();
                			}
                		}
                		imageSuivante();
                		Thread.sleep(4000);
                	} catch (InterruptedException ie) {
                		System.err.println("pas cool");
                	}

                }
            }
        }).start();
    }

    public void imagePrecedente() {
        if (iterator.hasPrevious()) {
            PikImage pik = null;
            inRotation = false;
            try {
                nextImage = currentImage;
                if (prevImage != null) {
                    currentImage = prevImage;
                    iterator.previous();
                    prevImage = null;
                } else {
                    pik = iterator.previous();
                    currentImage = rescaleImage(pik.getImage());
                }
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        diaporama.setIcon(new ImageIcon(currentImage));
                    }
                });
                if (!iterator.hasPrevious()) {
                    prec.setEnabled(false);
                    preced.setEnabled(false);
                }
                if (!suiv.isEnabled()) {
                    suiv.setEnabled(true);
                    suivant.setEnabled(true);
                }
            } catch (IOException ioe) {
                JOptionPane.showMessageDialog(this,
                    "Impossible d'ouvrir l'image "
                    + pik.getPath() + " !", "Erreur !",
                    JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    public synchronized void imageSuivante() {
        if (iterator.hasNext()) {
            inRotation = false;
            PikImage pik = null;
            try {
                prevImage = currentImage;
                if (nextImage != null) {
                    currentImage = nextImage;
                    iterator.next();
                    nextImage = null;
                } else {
                    pik = iterator.next();
                    currentImage = rescaleImage(pik.getImage());
                }
                SwingUtilities.invokeLater(new Runnable() {

                    public void run() {
                        diaporama.setIcon(new ImageIcon(currentImage));
                    }
                });
                if (!prec.isEnabled()) {
                    prec.setEnabled(true);
                    preced.setEnabled(true);
                }
                if (!iterator.hasNext()) {
                    suiv.setEnabled(false);
                    suivant.setEnabled(false);
                }
            } catch (IOException ioe) {
                JOptionPane.showMessageDialog(this,
                    "Impossible d'ouvrir l'image "
                    + pik.getPath() + " !", "Erreur !",
                    JOptionPane.ERROR_MESSAGE);
            }
        }
    }

    private BufferedImage rescaleImage(BufferedImage bi) {
        double sc1,sc2;
        sc1 = ((double) diaporama.getWidth()) / bi.getWidth();
        sc2 = ((double) diaporama.getHeight()) / bi.getHeight();
        double sc = Math.min(sc1, sc2);
        if (sc < 1) {
        	RescaleTraitement rt = new RescaleTraitement(bi, sc, sc,RescaleTraitement.TYPE_BILINEAR);
            return rt.executeTraitement();
        } else {
            return bi;
        }
    }

    public void rotateLeft() {
        if (!inRotation) {
            rotate = new RotateTraitement(currentImage, 0);
            inRotation = true;
        }
        rotate.setAngle(rotate.getAngle() - 90);
        currentImage = rescaleImage(rotate.executeTraitement());
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                diaporama.setIcon(new ImageIcon(currentImage));
            }
        });
    }

    public void rotateRight() {
        if (!inRotation) {
            rotate = new RotateTraitement(currentImage, 0);
            inRotation = true;
        }
        rotate.setAngle(rotate.getAngle() + 90);
        currentImage = rescaleImage(rotate.executeTraitement());
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                diaporama.setIcon(new ImageIcon(currentImage));
            }
        });
    }

}
